#include "threadpool.h"

#include<assert.h>
using namespace linch;

ThreadPool::ThreadPool(const std::string& name)
    :m_name(name),
    m_maxQueueSize(0),
    m_runing(false)
{

}

ThreadPool::~ThreadPool()
{
    if (m_runing)
    {
        stop();
    }
}

void ThreadPool::start(int count)
{
    assert(m_threads.empty());
    assert(count >= 0);

    m_runing = true;
    m_threads.reserve(count);

    for (int i = 0; i < count; ++i)
    {
        m_threads.push_back(new std::thread(&ThreadPool::runInThread, this));
    }
    if (count == 0)
    {
        m_threadInitCallback();
    }
}

void ThreadPool::stop()
{
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_runing = false;
        //唤醒所有的工作线程
        m_notEmpty.notify_all();
    }
    //等待所有线程退出
    for(auto pThread : m_threads)
    {
        pThread->join();
    }
}

size_t ThreadPool::getQueueSize() const
{
    std::lock_guard<std::mutex> lock(m_mutex);
    return m_queue.size();
}

void ThreadPool::run(const Task &func)
{
    if (!func)
    {
        return;
    }
    if (m_threads.empty())
    {
        func();
    }
    else
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_notFull.wait(lock,[&](){ return !isFull();});

        m_queue.push_back(func);
        lock.unlock();
        m_notEmpty.notify_one();
    }
}

ThreadPool::Task ThreadPool::take()
{
    std::unique_lock<std::mutex> lock(m_mutex);
    m_notEmpty.wait(lock, [&](){return !m_queue.empty() || ! m_runing; });

    Task task;
    if (!m_queue.empty())
    {
        task = m_queue.front();
        m_queue.pop_front();
        if (m_maxQueueSize > 0)
        {
            lock.unlock();
            m_notFull.notify_one();
        }
    }

    return task;
}

bool ThreadPool::isFull() const
{
    printf("id:%u, size:%u \n",std::this_thread::get_id(), m_queue.size());

    return m_maxQueueSize > 0 && m_queue.size() >= m_maxQueueSize;
}

void ThreadPool::runInThread()
{
    try {
        if (m_threadInitCallback)
        {
            m_threadInitCallback();
        }
        while(m_runing)
        {
            Task func(take());
            if (func)
            {
                func();
            }
        }
    }  catch (...) {
        throw;
    }
}






















